<?php

class Account_Model_Registration
{
	const IDNAME_TAKEN = 'idnameTaken';
	const IDNAME_RESERVED = 'idnameReserved';
	const EMAIL_USED = 'emailUsed';


	// Static salt for account code
	protected $_codeSalt = 'EUSO';

	protected $_errorCodes = array();


	/**
	 * Register an account.
	 */
	public function register($accInfo = null)
	{
		$this->_errorCodes = array();

		if (!is_array($accInfo)) {
			throw new Exception('Invalid account information');
		}
		if (empty($accInfo['idname'])) {
			throw new Exception('Username could not be empty');
		}
		if (empty($accInfo['email'])) {
			throw new Exception('Email address could not  be empty');
		}


		$opts = Kernel::getInstance()->getOptions();

		$activationMethod = 'admin';
		if (is_array($opts['account'])) {
			$accOpts = $opts['account'];
			if (is_array($accOpts['activation']) && isset($accOpts['activation']['method'])) {
				$activationMethod = $accOpts['activation']['method'];
			}
		}


		$table = Account_Model_DbTable_Account::getInstance();

		// Check for existing idname and/or email address
		$select = $table->select();
		$select->where('idname= ?', strtolower($accInfo['idname']));
		$select->orWhere('email= ?', strtolower($accInfo['email']));

		$dbResult = $table->fetchAll($select);

		if ($dbResult->count() > 0) {

			$nameUsed = FALSE;
			$emailUsed = FALSE;

			foreach ($dbResult as $dbRow) {
				if ($dbRow->idname == $accInfo['idname']) {
					$nameUsed = TRUE;
				}
				if ($dbRow->email == $accInfo['email']) {
					$emailUsed = TRUE;
				}
			}

			if ($nameUsed) {
				$this->_errorCodes[] = self::IDNAME_TAKEN;
			}
			if ($emailUsed) {
				$this->_errorCodes[] = self::EMAIL_USED;
			}
		}
		//TODO: check for reserved names

		if (count($this->_errorCodes) > 0) {
			return FALSE;
		}


		$salt = sprintf("%x", crc32(md5(uniqid(rand(), TRUE))));
		if ($activationMethod == 'auto') {
			$activationKey = NULL;
		} else {
			$activationKey = md5(sha1(microtime()));
		}


        $dbData = array(
			'idname'    => strtolower($accInfo['idname']),
            'email'     => strtolower($accInfo['email']),
			'code'      => md5($this->_codeSalt . $accInfo['email']),
			'salt'      => $salt,
            'passkey'   => md5($salt . sha1($accInfo['password'])),
            'register_time' => time() - date('Z'),
			'nicename'  => $accInfo['idname'],
        );

		$insertId = $table->insert($dbData);
		//CHECK: can we use this id?
		if (intval($insertId) === 0) {
			throw new Exception('Query error');
		}

		// Assign the ID
		$accountId = $table->getAdapter()->lastInsertId();


		if (empty($activationKey) === FALSE)
		{
			$statusTable = Account_Model_DbTable_Status::getInstance();
			$statusDbData = array(
				'account_id'=> $accountId,
				'assign_time'  => time() - date('Z'),
				'status'    => 'pending',
				'param'     => $activationKey,
			);

			$insertId = $statusTable->insert($statusDbData);
			//CHECK: can we use this id?
			if (intval($insertId) === 0) {
				throw new Exception('Query error');
			}
		}


		$site_name = Kernel::getInstance()->getSiteName();
		$site_url = site_url();
		$username = $dbData['nicename'];
		$identity = $dbData['nicename'];
		$usermail = $dbData['email'];
		$password = $accInfo['password'];
		$activation_key = $activationKey;
		$activation_url = site_url() .'/account/activate';
		$activation_urlkey = $activation_url .'/code/'. $activation_key;

		$site_email = $opts['site']['administrator']['email'];

		ob_start();
		if ($activationMethod == 'email') {
			require CORE_PATH .'/account/mails/ActivationKey.php';
		} else if ($activationMethod == 'auto') {
			require CORE_PATH .'/account/mails/Ready.php';
		} else {
			require CORE_PATH .'/account/mails/Pending.php';
		}
		$mailBody = ob_get_clean();

		//DEV: email address override
		@include '../mailaddr.php';

		$mail = new Euso_Model_Mail();
		$mail->setBodyText($mailBody)
			->setFrom($site_email, $site_name)
			->addTo($usermail, $dbData['nicename'])
			->setSubject($site_name .' Account Registration')
		;

		$mail->send();


		return true;
	}

	public function getErrorCodes()
	{
		return $this->_errorCodes;
	}
}